/*******************************************************************************
 * Copyright (c) 2010 Sylvain Sicard.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Sylvain Sicard - initial API and implementation
 ******************************************************************************/
package com.googlecode.ssdutils.jlauncher;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.scannotation.AnnotationDB;
import org.scannotation.ClasspathUrlFinder;

import com.googlecode.ssdutils.jlauncher.annotations.Launcher;
import com.googlecode.ssdutils.jlauncher.annotations.Option;

/**
 * @author Sylvain Sicard
 * 
 */
public class AnnotationsReader {

	protected static final String LAUNCHER_ANNOTATION = Launcher.class
			.getName();

	protected Class<?> getClassByName(String className)
			throws ClassNotFoundException {
		return this.getClass().getClassLoader().loadClass(className);
	}

	/**
	 * @param strings
	 * @return
	 * @throws IOException
	 */
	public Set<String> getLauncherClasses() throws IOException {
		URL[] urls = ClasspathUrlFinder.findClassPaths();
		AnnotationDB annotationDB = new AnnotationDB();
		annotationDB.scanArchives(urls);
		Map<String, Set<String>> annotationIndex = annotationDB
				.getAnnotationIndex();
		return annotationIndex.get(LAUNCHER_ANNOTATION);
	}

	public Set<Field> getOptions(Class<?> launcherClazz) {
		Set<Field> options = new HashSet<Field>();
		for (Field f : launcherClazz.getDeclaredFields()) {
			Option o = f.getAnnotation(Option.class);
			if (o != null) {
				options.add(f);
			}
		}
		return options;
	}

	public Set<Method> getLauncherMethods(Class<?> launcherClazz) {
		Set<Method> launchers = new HashSet<Method>();
		for (Method m : launcherClazz.getDeclaredMethods()) {
			Launcher l = m.getAnnotation(Launcher.class);
			if (l != null) {
				launchers.add(m);
			}
		}
		return launchers;
	}

	/**
	 * @return
	 * @throws ClassNotFoundException
	 * @throws IOException
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 */
	public Set<LaunchConfiguration> getLaunchConfiguration()
			throws IOException, ClassNotFoundException, InstantiationException,
			IllegalAccessException {
		Set<LaunchConfiguration> configs = new HashSet<LaunchConfiguration>();
		ClassLoader cl = getClass().getClassLoader();
		for (String runnerClasse : getLauncherClasses()) {
			LaunchConfiguration config = new LaunchConfiguration();
			Class<?> clazz = cl.loadClass(runnerClasse);
			config.setRunner(clazz);
			config.setLaunchers(getLauncherMethods(clazz));
			config.setOptions(getOptions(clazz));
			configs.add(config);
		}
		return configs;
	}
}
